<template>
  <a-layout>
    <a-layout-content style="padding: 24px;" >
      <a-modal v-model:visible="isIfNeedWatermarkModalVisible"
               title="是否需要添加水印？"
      >
        <p>
          文件即将开始上传，上传后是否需要添加水印？
        </p>
        <template v-slot:footer>
          <a-button @click="handleUploadFolder(0)">不需要</a-button>
          <a-button type="primary" @click="handleUploadFolder(1)">需要</a-button>
        </template>
      </a-modal>

      <div>
        <a-row class="headRow">
          <a-col :span="12">
            <a-select v-model:value="status" style="width: 200px;" @change="onSelectChange">
              <a-select-option value="published">已发布</a-select-option>
              <a-select-option value="unpublished">未发布</a-select-option>
            </a-select>
          </a-col>
          <a-col>
            <a-button @click="handleUploadExperimentSet">新建实验集</a-button>
          </a-col>
          <a-col>
            <a-space direction="horizontal" style="margin-left: 20px">
              <a-button type="primary" @click="triggerFileInput">选择实验集压缩包</a-button>
              <input type="file" ref="fileInput" @change="handleFileChange" hidden="hidden"/>
              <a-button type="primary" @click="showIfNeedWatermarkModal" :disabled="isUploadButtonDisable">上传</a-button>
              <span style="max-width: 50px">{{fileSelectMessage}}</span>
            </a-space>
          </a-col>
        </a-row>
      </div>

      <!-- 进度显示区域 -->
      <div v-if="uploadProgress > 0 || processingProgress.experimentSetId" class="progress-mask"></div>
      <div v-if="uploadProgress > 0 || processingProgress.experimentSetId" class="progress-container">
          <!-- 调试信息 -->
          <div style="margin-bottom: 10px; color: #666;">
            <div>uploadProgress: {{ uploadProgress }}</div>
            <div>experimentSetId: {{ processingProgress.experimentSetId }}</div>
            <div>metadataProgress: {{ processingProgress.metadataProgress }}</div>
            <div>chainProgress: {{ processingProgress.chainProgress }}</div>
          </div>
          <!-- 上传进度 -->
          <a-progress
              v-if="uploadProgress > 0"
              :percent="uploadProgress"
              :status="uploadStatus"
              :format="percent => `上传进度: ${percent}% (${uploadedSize}/${totalSize})`"
          />

          <!-- 处理进度 -->
          <template v-if="processingProgress.experimentSetId">
            <!-- 调试信息 -->
            <div class="debug-info">
              <pre>{{ processingProgress }}</pre>
            </div>

            <!-- 元数据处理进度 -->
            <a-progress
                class="processing-progress"
                :percent="processingProgress.metadataProgress"
                :status="processingProgress.metadataCompleted ? 'success' : 'active'"
                :format="percent => `元数据提取: ${percent}% (${processingProgress.metadataProcessedFiles}/${processingProgress.totalFiles})`"
            />

            <!-- 上链处理进度 -->
            <a-progress
                class="processing-progress"
                :percent="processingProgress.chainProgress"
                :status="processingProgress.chainCompleted ? 'success' : (processingProgress.metadataCompleted ? 'active' : '')"
                :format="percent => `数据上链: ${percent}% (${processingProgress.chainProcessedFiles}/${processingProgress.totalFiles})`"
            />
          </template>
        </div>
      </div>

      <!-- 表格内容 -->
      <a-table :columns="columns" :data-source="currentTableData" :pagination="false" :scroll="{y:'65vh'}">
        <template #bodyCell="{column, record}">
          <template v-if="column.key === 'action' ">
              <span>
                <a @click="handleCheckDetail(record)">点击进入</a>
                <a-divider type="vertical" />
                <template v-if="status === 'unpublished'">
                  <a :class="{ disabled: isPublishing || processingIds.has(record.experiment_set_id) }"
                     @click="(!isPublishing && !processingIds.has(record.experiment_set_id)) && handlePublish(record)">
                     {{ processingIds.has(record.experiment_set_id) ? '处理中' : '发布' }}
                  </a>
                </template>
                <template v-else>
                  <a class="disabled">已发布</a>
                </template>
                <a-divider type="vertical" />
                <a @click="handleDownload(record)">下载</a>
              </span>
          </template>
        </template>
      </a-table>
    </a-layout-content>
  </a-layout>
</template>

<script>
import { defineComponent } from 'vue';
import {Layout, Table, Button, Space} from 'ant-design-vue';
import { Modal } from 'ant-design-vue';
import axiosInstance from "@/axios/axios.js";
import {v4 as uuidv4} from "uuid";
import SockJS from 'sockjs-client';
import Stomp from 'webstomp-client';

const message = Modal.success;

const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
const MAX_CONCURRENT_UPLOADS = 3; // 最大并发上传数

export default defineComponent({
  name: 'MyDataExperimentSet',
  components: {},
  data() {
    return {
      loading: false,
      isPublishing: false,
      status: "unpublished",
      publishedData: [],
      unpublishedData: [],
      stompClient: null,
      wsConnected: false,
      columns: [
        {
          title: '实验数据集名',
          dataIndex: 'name',
          key: 'name'
        },
        {
          title: '描述',
          dataIndex: 'description',
          key: 'description'
        },
        {
          title: '实验者',
          dataIndex: 'creator',
          key: 'creator'
        },
        {
          title: '领域',
          dataIndex: 'field',
          key: 'field'
        },
        {
          title: '操作',
          key: 'action',
          scopedSlots: {customRender: 'action'}
        }
      ],
      files: [],
      loadingAlert: null,
      fileSelectMessage: "",
      isUploadButtonDisable: true,
      ifNeedWatermark: 0,
      isIfNeedWatermarkModalVisible: false,
      uploadProgress: 0,
      uploadStatus: 'active',
      uploadedSize: '0MB',
      totalSize: '0MB',
      compressedFile: null,
      folderName: "",
      uploadRetries: 3, // 上传重试次数
      retryDelay: 1000, // 重试延迟（毫秒）
      processingIds: new Set(), // 正在处理的实验集ID
      processingProgress: {
        experimentSetId: '',
        totalFiles: 0,
        metadataProcessedFiles: 0,
        chainProcessedFiles: 0,
        metadataProgress: 0,
        chainProgress: 0,
        metadataCompleted: false,
        chainCompleted: false,
        hasFailure: false
      },
      progressTimer: null, // 进度查询定时器
    };
  },
  created() {
    // 检查登录状态
    if (!this.$cookies.get('jwt') || !sessionStorage.getItem("isLogin")) {
      Modal.warning({ content: '请先登录' });
      this.$router.push('/login');
      return;
    }
  },
  beforeDestroy() {
    // 清理定时器和状态
    this.cleanupProgress();
    // 断开WebSocket连接
    this.disconnectWebSocket();
  },
  beforeRouteLeave(to, from, next) {
    // 路由离开时清理
    this.cleanupProgress();
    // 断开WebSocket连接
    this.disconnectWebSocket();
    next();
  },
  async mounted() {
    // 检查必要的cookie是否存在
    const requiredCookies = ['jwt', 'username'];
    const missingCookies = requiredCookies.filter(cookie => !this.$cookies.get(cookie));
    
    if (missingCookies.length > 0) {
      Modal.error({ content: '登录信息不完整，请重新登录' });
      this.$router.push('/login');
      return;
    }

    // 建立WebSocket连接
    this.connectWebSocket();

    // 只获取初始状态（未发布）的数据
    if (this.loading) return;

    this.loading = true;
    try {
      const response = await axiosInstance({
        method: "POST",
        url: "/myData/getExperimentSetsNotPublished",
        data: {
          username: this.$cookies.get("username")
        }
      });

      const unpublishedData = [...(response.data.data || [])];
      this.unpublishedData = unpublishedData.map(item => ({
        ...item,
        processing: this.processingIds.has(item.experiment_set_id)
      }));
    } catch (error) {
      console.error('获取数据失败:', error);
      console.error(`获取数据失败: ${error.response?.data?.message || error.message}`);
    } finally {
      this.loading = false;
    }
  },
  computed: {
    currentTableData() {
      const publishedData = Array.isArray(this.publishedData) ? [...this.publishedData] : [];
      const unpublishedData = Array.isArray(this.unpublishedData) ? [...this.unpublishedData] : [];
      return this.status === 'published' ? publishedData : unpublishedData;
    },
    isPublished() {
      return (record) => this.status === 'published';
    }
  },
  methods: {
    // WebSocket相关方法
    connectWebSocket(retryCount = 0) {
      const maxRetries = 3;
      const retryDelay = 2000;

      try {
        const username = this.$cookies.get("username");
        if (!username) {
          console.error('未找到用户名，无法建立WebSocket连接');
          return;
        }

        console.log('准备建立WebSocket连接，尝试次数:', retryCount + 1);
        const socket = new SockJS('/ws');
        this.stompClient = Stomp.over(socket);

        // 设置STOMP连接头
        const connectHeaders = {
          username: username,
          jwt: this.$cookies.get('jwt')
        };

        this.stompClient.connect(connectHeaders, () => {
          this.wsConnected = true;
          console.log('WebSocket连接成功');
          
          // 订阅用户特定的主题
          const topic = `/topic/user/${username}/experimentSet`;
          console.log('订阅主题:', topic);
          this.stompClient.subscribe(topic, this.handleExperimentSetMessage);

          // 添加连接断开监听
          this.stompClient.ws.onclose = () => {
            console.log('WebSocket连接断开，准备重连');
            this.wsConnected = false;
            this.stompClient = null;
            
            // 如果还没有超过最大重试次数，则重试
            if (retryCount < maxRetries) {
              console.log(`${retryDelay/1000}秒后进行第${retryCount + 2}次重试...`);
              setTimeout(() => {
                this.connectWebSocket(retryCount + 1);
              }, retryDelay);
            } else {
              console.error('WebSocket连接失败，已达到最大重试次数');
              console.error('WebSocket连接断开，请刷新页面重试');
            }
          };
        }, (error) => {
          console.error('WebSocket连接失败:', error);
          this.wsConnected = false;
          this.stompClient = null;

          // 如果还没有超过最大重试次数，则重试
          if (retryCount < maxRetries) {
            console.log(`${retryDelay/1000}秒后进行第${retryCount + 2}次重试...`);
            setTimeout(() => {
              this.connectWebSocket(retryCount + 1);
            }, retryDelay);
          } else {
            console.error('WebSocket连接失败，已达到最大重试次数');
            console.error('WebSocket连接失败，请刷新页面重试');
          }
        });

        // 添加错误处理
        socket.onerror = (error) => {
          console.error('SockJS错误:', error);
        };
      } catch (error) {
        console.error('建立WebSocket连接时发生错误:', error);
        this.wsConnected = false;
        this.stompClient = null;
      }
      // 已经在上面创建了stompClient并连接，这里不需要重复
    },

    disconnectWebSocket() {
      if (this.stompClient && this.wsConnected) {
        try {
          this.stompClient.disconnect();
          console.log('WebSocket断开连接');
        } catch (error) {
          console.error('断开WebSocket连接失败:', error);
        }
        this.wsConnected = false;
        this.stompClient = null;
      }
    },

    handleExperimentSetMessage(message) {
      try {
        console.log('收到WebSocket消息:', message);
        const data = JSON.parse(message.body);
        
        if (data.type === 'experimentSetCreated') {
          const experimentSetId = data.experimentSetId;
          console.log('实验集创建完成，ID:', experimentSetId);
          
          // 开始轮询处理进度
          this.processingIds.add(experimentSetId);
          this.startProgressPolling(experimentSetId);
          message({ content: '开始处理图片...' });
        }
      } catch (error) {
        console.error('处理WebSocket消息失败:', error);
      }
    },

    // 查询处理进度
    async fetchProcessingProgress(experimentSetId) {
      console.log('===== fetchProcessingProgress =====');
      console.log('开始查询处理进度，ID:', experimentSetId);
      try {
        console.log('发送请求前的processingProgress:', this.processingProgress);
        console.log('发送请求前的experimentSetId:', experimentSetId);
        
        const response = await axiosInstance({
          method: "GET",
          url: `/status/experiment-set/${experimentSetId}/summary`
        });

        console.log('收到处理状态响应:', {
          status: response.status,
          statusText: response.statusText,
          data: response.data
        });
        if (response.data && response.data.data) {
          const data = response.data.data;
          console.log('Processing data:', data);
          this.processingProgress = {
            experimentSetId,
            totalFiles: data.totalFiles || 0,
            metadataProcessedFiles: data.metadataProcessedFiles || 0,
            chainProcessedFiles: data.chainProcessedFiles || 0,
            metadataProgress: Math.round((data.metadataProcessedFiles / (data.totalFiles || 1)) * 100),
            chainProgress: Math.round((data.chainProcessedFiles / (data.totalFiles || 1)) * 100),
            metadataCompleted: data.metadataCompleted || false,
            chainCompleted: data.chainCompleted || false,
            hasFailure: data.hasFailure || false
          };
          console.log('Updated progress:', this.processingProgress);

          // 如果处理完成或失败，停止轮询
          if (response.data.chainCompleted || response.data.hasFailure) {
            if (this.progressTimer) {
              clearInterval(this.progressTimer);
              this.progressTimer = null;
            }
            // 从处理中列表移除
            this.processingIds.delete(experimentSetId);
            // 重置进度状态
            setTimeout(() => {
              this.processingProgress = {
                experimentSetId: '',
                totalFiles: 0,
                metadataProcessedFiles: 0,
                chainProcessedFiles: 0,
                metadataProgress: 0,
                chainProgress: 0,
                metadataCompleted: false,
                chainCompleted: false,
                hasFailure: false
              };
            }, 2000); // 延迟2秒后清除进度条，让用户能看到100%的状态
            // 显示结果
            if (response.data.hasFailure) {
              console.error('处理失败');
            } else {
              message.success('处理完成！');
            }
          }
        }
      } catch (error) {
        console.error('获取处理进度失败:', error);
      }
    },

    // 清理进度状态和定时器
    cleanupProgress() {
      if (this.progressTimer) {
        clearInterval(this.progressTimer);
        this.progressTimer = null;
      }
      this.processingProgress = {
        experimentSetId: '',
        totalFiles: 0,
        metadataProcessedFiles: 0,
        chainProcessedFiles: 0,
        metadataProgress: 0,
        chainProgress: 0,
        metadataCompleted: false,
        chainCompleted: false,
        hasFailure: false
      };
      this.processingIds.clear();
    },

    // 开始轮询处理进度
    startProgressPolling(experimentSetId) {
      console.log('===== startProgressPolling =====');
      console.log('传入的experimentSetId:', experimentSetId);
      
      // 清理可能存在的旧定时器
      if (this.progressTimer) {
        console.log('清理旧定时器');
        clearInterval(this.progressTimer);
      }

      // 初始化进度状态并确保设置experimentSetId
      console.log('初始化进度状态');
      this.processingProgress = {
        experimentSetId: experimentSetId, // 确保设置experimentSetId
        totalFiles: 0,
        metadataProcessedFiles: 0,
        chainProcessedFiles: 0,
        metadataProgress: 0,
        chainProgress: 0,
        metadataCompleted: false,
        chainCompleted: false,
        hasFailure: false
      };

      console.log('Starting progress polling with ID:', experimentSetId);
      console.log('Initial progress state:', this.processingProgress);

      // 立即查询一次
      this.fetchProcessingProgress(experimentSetId);

      // 设置定时查询
      this.progressTimer = setInterval(() => {
        this.fetchProcessingProgress(experimentSetId);
      }, 2000); // 每2秒查询一次
    },

    formatSize(bytes) {
      if (bytes === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    },
    async fetchData() {
      if (this.loading) return;

      this.loading = true;
      try {
        // 分别获取已发布和未发布的数据
        const [publishedResponse, unpublishedResponse] = await Promise.all([
          axiosInstance({
            method: "POST",
            url: "/myData/getExperimentSetsPublished",
            data: {
              username: this.$cookies.get("username")
            }
          }),
          axiosInstance({
            method: "POST",
            url: "/myData/getExperimentSetsNotPublished",
            data: {
              username: this.$cookies.get("username")
            }
          })
        ]);

        this.publishedData = [...(publishedResponse.data.data || [])];
        this.unpublishedData = [...(unpublishedResponse.data.data || [])];
      } catch (error) {
        console.error('获取数据失败:', error);
        console.error(`获取数据失败: ${error.response?.data?.message || error.message}`);
      } finally {
        this.loading = false;
      }
    },
    handleCheckDetail(record) {
      if (!record.experiment_set_id) {
        console.error('实验集ID不存在');
        return;
      }

      this.$router.push({
        path: '/MyData/Batch',
        query: {
          experiment_set_id: record.experiment_set_id,
          experiment_set_name: record.name
        }
      });
    },
    async handlePublish(record) {
      if (this.isPublishing) return;

      this.isPublishing = true;
      try {
        await axiosInstance({
          method: "POST",
          url: "/myData/publish",
          data: {
            username: this.$cookies.get("username"),
            dataId: record.experiment_set_id,
          },
        });

        // 只获取未发布的数据
        const response = await axiosInstance({
          method: "POST",
          url: "/myData/getExperimentSetsNotPublished",
          data: {
            username: this.$cookies.get("username")
          }
        });

        this.unpublishedData = [...(response.data.data || [])];
        this.status = 'unpublished';
        message.success('发布成功');
      } catch (error) {
        console.error('发布失败:', error);
        console.error(`发布失败: ${error.response?.data?.message || error.message}`);
      } finally {
        this.isPublishing = false;
      }
    },
    async onSelectChange(value) {
      if (this.loading) return;

      this.loading = true;
      try {
        const url = value === 'published' ?
            "/myData/getExperimentSetsPublished" :
            "/myData/getExperimentSetsNotPublished";

        const response = await axiosInstance({
          method: "POST",
          url: url,
          data: {
            username: this.$cookies.get("username")
          }
        });

        if (value === 'published') {
          this.publishedData = [...(response.data.data || [])];
        } else {
          const unpublishedData = [...(response.data.data || [])];
          this.unpublishedData = unpublishedData.map(item => ({
            ...item,
            processing: this.processingIds.has(item.experiment_set_id)
          }));
        }
      } catch (error) {
        console.error('获取数据失败:', error);
        console.error(`获取数据失败: ${error.response?.data?.message || error.message}`);
      } finally {
        this.loading = false;
      }
    },
    async handleDownload(record) {
      try {
        const response = await axiosInstance({
          method: "POST",
          url: "/download/experimentSet",
          data: {
            username: this.$cookies.get("username"),
            experimentSetName: record.name
          },
        });

        if (response.data && response.data.data) {
          const link = document.createElement('a');
          link.href = response.data.data;
          link.setAttribute('download', '');
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          message.success('下载开始');
        }
      } catch (error) {
        console.error('下载失败:', error);
        console.error(`下载失败: ${error.response?.data?.message || error.message}`);
      }
    },
    handleUploadExperimentSet() {
      this.$router.push({
        path: '/UploadExperimentSet',
      });
    },
    showIfNeedWatermarkModal() {
      this.isIfNeedWatermarkModalVisible = true;
    },
    async handleUploadFolder(needWatermark) {
      this.isIfNeedWatermarkModalVisible = false;
      this.ifNeedWatermark = needWatermark;

      const totalChunks = Math.ceil(this.compressedFile.size / CHUNK_SIZE);
      const fileId = uuidv4();

      this.uploadProgress = 0;
      this.uploadStatus = 'active';
      this.totalSize = this.formatSize(this.compressedFile.size);
      this.uploadedSize = '0MB';

      let uploadedChunks = 0;
      const updateProgress = (chunkSize) => {
        uploadedChunks++;
        this.uploadProgress = Math.round((uploadedChunks / totalChunks) * 100);
        this.uploadedSize = this.formatSize(uploadedChunks * chunkSize);
      };

      const uploadChunk = async (chunkIndex, retries = this.uploadRetries) => {
        const start = chunkIndex * CHUNK_SIZE;
        const end = Math.min(start + CHUNK_SIZE, this.compressedFile.size);
        const chunk = this.compressedFile.slice(start, end);

        const formData = new FormData();
        formData.append("username", this.$cookies.get("username"));
        formData.append("ifWatermark", this.ifNeedWatermark);
        formData.append("fileId", fileId);
        formData.append("chunkIndex", chunkIndex);
        formData.append("totalChunks", totalChunks);
        formData.append("folderName", this.folderName);
        formData.append("chunk", chunk);

        try {
          const response = await axiosInstance.post("/upload/chunk", formData);
          if (response.data.code === 200) {
            updateProgress(chunk.size);
          } else {
            throw new Error(response.data.message || '上传失败');
          }
        } catch (error) {
          console.error(`分片 ${chunkIndex} 上传失败:`, error);

          if (retries > 0) {
            console.warn(`上传分片 ${chunkIndex} 失败，剩余重试次数: ${retries - 1}`);
            await new Promise(resolve => setTimeout(resolve, this.retryDelay));
            return uploadChunk(chunkIndex, retries - 1);
          }

          throw error;
        }
      };

      const uploadAllChunks = async () => {
        const chunks = Array.from({ length: totalChunks }, (_, i) => i);
        const failedChunks = [];

        // 使用分组上传来控制并发
        for (let i = 0; i < chunks.length; i += MAX_CONCURRENT_UPLOADS) {
          const group = chunks.slice(i, i + MAX_CONCURRENT_UPLOADS);
          const uploadPromises = group.map(chunkIndex =>
              uploadChunk(chunkIndex).catch(error => {
                failedChunks.push({ chunkIndex, error });
                return null;
              })
          );

          await Promise.all(uploadPromises);

          // 如果有失败的分片，立即停止上传
          if (failedChunks.length > 0) {
            const errors = failedChunks.map(({ chunkIndex, error }) =>
                `分片 ${chunkIndex}: ${error.message}`
            ).join('\n');
            throw new Error(`上传失败:\n${errors}`);
          }
        }
      };

      try {
        await uploadAllChunks();
        this.uploadStatus = 'success';
        message.success("文件夹上传成功！");
        this.fileSelectMessage = '';
        this.compressedFile = null;
        
        // 等待后端处理并通过消息通知
        message({ content: '等待处理...' });
      } catch (error) {
        this.uploadStatus = 'exception';
        console.error(error.message);
      }
    },
    triggerFileInput() {
      this.$refs.fileInput.click();
    },
    async handleFileChange(event) {
      const file = event.target.files[0];
      if (!file) return;

      // 检查文件大小
      if (file.size > MAX_FILE_SIZE) {
        console.error(`文件大小不能超过${this.formatSize(MAX_FILE_SIZE)}`);
        return;
      }

      this.compressedFile = file;
      const fullFileName = this.compressedFile.name;
      console.log('handleFileChange - 原始文件名:', fullFileName);
      const fileSuffix = fullFileName.split('.').pop();
      console.log('handleFileChange - 文件后缀:', fileSuffix);
      const fileNameWithoutSuffix = fullFileName.substring(0, fullFileName.lastIndexOf('.'));
      console.log('handleFileChange - 不带后缀的文件名:', fileNameWithoutSuffix);
      this.folderName = fullFileName;
      console.log('handleFileChange - 设置的folderName:', this.folderName);

      if ('zip' !== fileSuffix) {
        console.error("只能上传.zip压缩文件！");
        return;
      }

      const requestPath = this.$cookies.get("username") + "/" + fileNameWithoutSuffix;
      const encodeRelativePath = encodeURIComponent(requestPath);

      try {
        const response = await axiosInstance({
          method: "GET",
          url: "/common/getIfFileExist?relativePath=" + encodeRelativePath,
        });

        if (response.data.data === 'exist') {
          console.error("实验集名称已存在！");
          this.compressedFile = null;
          this.fileSelectMessage = '';
          this.isUploadButtonDisable = true;
        } else {
          this.fileSelectMessage = `选中文件：${fullFileName} (${this.formatSize(file.size)})`;
          this.isUploadButtonDisable = false;
        }
      } catch (error) {
        console.error('检查文件是否存在失败:', error);
        console.error(`检查文件失败: ${error.response?.data?.message || error.message}`);
      }
    },
  }
});
</script>

<style scoped>
.headRow {
  margin: 20px;
}
.disabled {
  pointer-events: none;
  opacity: 0.5;
}
.progress-container {
  position: fixed;
  top: 100px;
  left: 50%;
  transform: translateX(-50%);
  width: 80%;
  max-width: 800px;
  margin: 20px 0;
  padding: 20px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  z-index: 1000;
}

.progress-container :deep(.ant-progress) {
  margin-bottom: 12px;
}

.progress-container :deep(.ant-progress:last-child) {
  margin-bottom: 0;
}

.progress-container :deep(.ant-progress-text) {
  font-weight: 500;
}

.processing-progress {
  margin-top: 20px;
}

.debug-info {
  margin: 10px 0;
  padding: 10px;
  background: #fff;
  border: 1px solid #eee;
  border-radius: 4px;
  font-family: monospace;
  font-size: 12px;
}

.debug-info pre {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-all;
}
</style>
